using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using NetProtocol.POD;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 实体的主控制器，主要管理实体生命周期等
    /// </summary>
    public partial class LevelPlayEntityCtrl : LevelPlaySubBaseCtrl
    {
        #region private fields
        /// <summary>
        /// 主角实体
        /// </summary>
        private LevelCharacterEntity _characterEntity;
        /// <summary>
        /// 四叉树查询
        /// </summary>
        private QuadTree<LevelPlayBaseEntity> _entityQuadTree;
        /// <summary>
        /// 带trigger区域的实体 BVH查询树，aabb来查询
        /// </summary>
        private BVHTree2D<LevelPlayBaseEntity> _triggerBVHTree;
        /// <summary>
        /// 掉落物表现
        /// </summary>
        private List<DropItemPlay> _dropItemPlays = new();
        /// <summary>
        /// 正在死亡的实体
        /// </summary>
        private Dictionary<int, uint> _deadingEntitys = new Dictionary<int, uint>();
        /// <summary>
        /// 交互指示器正在指示的实体
        /// </summary>
        private LevelPlayRealityEntity _indicateEntity;
        #endregion private fields

        #region properties
        /// <summary>
        /// 实体的Holder parent
        /// </summary>
        public Transform entityHolder { private set; get; }
        /// <summary>
        /// 所有英雄实体
        /// </summary>
        public Dictionary<int, LevelCharacterEntity> heroEntities { get; set; } = new Dictionary<int, LevelCharacterEntity>();
        /// <summary>
        /// 所有的非主角实体
        /// </summary>
        public Dictionary<int, LevelPlayBaseEntity> entitys { get; set; } = new Dictionary<int, LevelPlayBaseEntity>();
        /// <summary>
        /// mcid和非主角实体的映射
        /// </summary>
        public Dictionary<int, List<LevelPlayBaseEntity>> mcidEntityMap { get; set; } = new();
        /// <summary>
        /// 所有的特殊实体参数处理器
        /// </summary>
        public DynParamProcessBase[] dynParamPrcoesses { get; private set; }
        /// <summary>
        /// 所有带触发范围的实体
        /// </summary>
        public Dictionary<LevelPlayBaseEntity, EntityParamTriggerRect> triggerRangeEntitys { get; set; } = new Dictionary<LevelPlayBaseEntity, EntityParamTriggerRect>();
        /// <summary>
        /// 交互头顶指示条
        /// </summary>
        public PositionConstraint headIndicator { protected set; get; }
        /// <summary>
        /// 交互锁定的实体（和交互指示器特效对应的实体基本一致，只是某些可交互实体不显示指示器）
        /// 该实体有值代表当前立刻按下交互按钮会和该实体交互，或当前正在和该实体交互
        /// </summary>
        public LevelPlayBaseEntity toInteractEntity { get; set; }
        #endregion properties

        public LevelPlayEntityCtrl()
        {
            AddMsgListener();
        }

        /// <summary>
        /// 获取主角
        /// </summary>
        public LevelCharacterEntity GetMainCharacter()
        {
            return _characterEntity;
        }

        #region 实体状态
        /// <summary>
        /// 通过dynLevelEntity添加实体
        /// </summary>
        /// <param name="dynEntity"></param>
        private async UniTask AddEntityByDynData(DynLevelEntity dynEntity)
        {
            //不存在创建新的
            var entity = LevelEntityFactory.CreateEntity(dynEntity);
            //id映射
            entitys.Add(entity.id, entity);
            //mcid映射
            if (!mcidEntityMap.TryGetValue(dynEntity.mcid, out var entityList))
            {
                entityList = ListPool<LevelPlayBaseEntity>.Get();
                mcidEntityMap.Add(dynEntity.mcid, entityList);
            }
            entityList.Add(entity);

            if (entity is LevelPlayRealityEntity normalEntity)
            {
                await normalEntity.LoadAndInstantiate(entityHolder);
                OnEntityCreate(entity);
            }
            else
            {
                OnEntityCreate(entity);
            }
        }

        /// <summary>
        /// 删除一个普通实体，包括显示和数据
        /// </summary>
        /// <param name="id">实体唯一标识</param>
        /// <param name="playDie">删除前是否播放死亡动画</param>
        private DynLevelEntity RemoveEntity(int id, bool playDie = true)
        {
            if (regionCtrl.levelRegion.RemoveDynEntity(id, out var dynEntity) && entitys.TryGetValue(id, out var e))
            {
                entitys.Remove(id);
                if (mcidEntityMap.TryGetValue(e.GetDynLevelEntity().mcid, out var entityList))
                {
                    entityList.Remove(e);
                }
                OnEntityDestroy(e, playDie);
                return dynEntity;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 设置实体的激活状态
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="active"></param>
        /// <param name="customActiveAnimId"></param>
        private void SetEntityActivation(LevelPlayBaseEntity entity, bool active, int customActiveAnimId = 0)
        {
            if (_deadingEntitys.TryGetValue(entity.id, out var timeId))
            {
                // 如果上次死亡动画还没播完,瞬间完成
                _deadingEntitys.Remove(entity.id);
                timeId.StopTimer(true);
            }

            if (active)
            {
                // active的时候
                entity.SetEntityActive(true);
                entity.RefreshQuestState();

                OnLevelEntityAdded(entity);

                // 播放出生动画
                var animationComponent = entity.GetAnimationComponent();
                if (animationComponent != null)
                {
                    // 指定了动画id的优先播
                    if (customActiveAnimId > 0)
                    {
                        animationComponent.StartAnimAction(customActiveAnimId);
                    }
                    else
                    {
                        var dynEntity = entity.GetDynLevelEntity();

                        // 如果是active带状态的情况下
                        if (dynEntity != null && dynEntity.activateWallActionPlay)
                        {
                            animationComponent.PlayStateOpenClose(!dynEntity.isObstacleActive);
                        }
                        else
                        {
                            animationComponent.PlayBorn();
                        }
                    }
                }
            }
            // deactive的时候 注意！该逻辑实际未调用，逻辑层目前deactive也是走的客户端的remove
            else
            {
                OnLevelEntityRemoved(entity);
                var animationComponent = entity.GetAnimationComponent();
                animationComponent?.ResetAnim();
                entity.SetEntityActive(false);
            }
        }

        /// <summary>
        /// 英雄实体创建的时候
        /// </summary>
        /// <param name="entity"></param>
        private void OnHeroEntityCreate(LevelCharacterEntity heroEntity)
        {
            heroEntity.OnEntityBirth();
            if (heroEntity.isMine)
            {
                regionCtrl.cameraCtrl.CharacterFllowLook(heroEntity.transform, heroEntity.transform);
                regionCtrl.interactCtrl.Active();
            }
        }

        /// <summary>
        /// 实体创建的时候
        /// </summary>
        /// <param name="entity"></param>
        private void OnEntityCreate(LevelPlayBaseEntity entity)
        {
            entity.OnEntityBirth();
            SetEntityActivation(entity, entity.active);
            var dynEntity = entity.GetDynLevelEntity();
            if (dynEntity.bindEffectResId != 0)
            {
                regionCtrl.effectCtrl.ShowEntityEffect(entity, (EntityBindPointCommonType)dynEntity.effectBindPoint, dynEntity.bindEffectResId).Forget();
            }
        }

        /// <summary>
        /// 实体销毁的时候
        /// </summary>
        /// <param name="entity"></param>
        private void OnEntityDestroy(LevelPlayBaseEntity entity, bool playDie)
        {
            entity.BroadcastComponentEvent(TComponentEvent.OnEntityObjectStartHide);
            MsgDispatcher.Broadcast<int>(MsgEventType.Level_EntityStartHide, entity.id);

            OnLevelEntityRemoved(entity);

            if (playDie)
            {
                //先播死亡动画，播完后销毁实体
                KillEntity(entity, true).Forget();
            }
            else
            {
                //直接销毁
                entity.Free();
            }
        }

        /// <summary>
        /// 执行播放动画后销毁实体的逻辑
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="needFree"></param>
        /// <returns></returns>
        private async UniTask KillEntity(LevelPlayBaseEntity entity, bool needFree)
        {
            var animationComponent = entity.GetAnimationComponent();
            if (animationComponent != null && animationComponent.PlayDie())
            {
                float time = 2.5f;
                var dynEntity = entity.GetDynLevelEntity();
                if (dynEntity != null && dynEntity.cfgLevelEntity != null)
                {
                    var cfgDuration = dynEntity.cfgLevelEntity.DieDuration;
                    time = cfgDuration > 0 ? cfgDuration.MillisecToSec() : time;
                }
                // 如果有死亡动画，等待死亡动画播放完毕
                var timerId = TimerManager.Instance.StartOneTimer(time);
                _deadingEntitys.Add(entity.id, timerId);
                await timerId.AwaitTimer();
                _deadingEntitys.Remove(entity.id);
            }

            if (needFree)
            {
                entity.Free();
            }
        }


        /// <summary>
        /// 使用四叉树查询实体
        /// </summary>
        /// <param name="returnObjects"></param>
        /// <param name="area"></param>
        public void QTRetrieveObjects(List<LevelPlayBaseEntity> returnObjects, Rect area)
        {
            _entityQuadTree.RetrieveObjects(returnObjects, area);
        }

        /// <summary>
        /// BVH 树查询数据
        /// </summary>
        /// <param name="returnObjects"></param>
        /// <param name="bounds"></param>
        public void BVHRetrieveObjects(List<LevelPlayBaseEntity> returnObjects, BVHBounds2D bounds)
        {
            _triggerBVHTree.RetrieveObjects(returnObjects, bounds);
        }

        /// <summary>
        /// 添加进可触发范围列表中
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="triggerRect"></param>
        public void AddEntityTriggerRange(LevelPlayBaseEntity entity, EntityParamTriggerRect triggerRect)
        {
            if (!triggerRangeEntitys.TryAdd(entity, triggerRect))
            {
                return;
            }
            //添加到BVH Tree
            var bvhBounds = entity.GetBVHBounds(triggerRect.rect, triggerRect.isRotatable);
            entity.bvhBounds = bvhBounds;
            _triggerBVHTree.Insert(entity);
        }

        /// <summary>
        /// 实体添加时,或者激活时
        /// </summary>
        /// <param name="entity"></param>
        protected void OnLevelEntityAdded(LevelPlayBaseEntity entity)
        {
            //添加实体到四叉树
            //TODO 忽略无交互的实体，如果实体有动态交互的时候再添加
            var v2 = GameMathUtil.LogicPos2UnityPosV2(entity.x, entity.z);
            entity.quadTreePos = v2;
            _entityQuadTree.Insert(entity);

            //添加实体时，对特殊的实体进行处理
            var dynEntity = entity.GetDynLevelEntity();
            if (dynEntity != null && dynEntity.levelEntityConfig != null)
            {
                IReadOnlyDictionary<EntityDynamicParamType, BaseEntityDynamicParam> paramMap = dynEntity.levelEntityConfig.paramMap;
                if (paramMap != null)
                {
                    foreach (var param in paramMap)
                    {
                        var process = dynParamPrcoesses[(int)param.Key];
                        if (process != null)
                        {
                            process.OnEntityAddProcess(entity, param.Value, paramMap);
                        }
                    }
                }
            }

            regionCtrl.displayObjCtrl.OnAddEntity(entity as LevelPlayRealityEntity);
        }

        /// <summary>
        /// 实体移除的时候
        /// </summary>
        /// <param name="entity"></param>
        protected void OnLevelEntityRemoved(LevelPlayBaseEntity entity)
        {
            regionCtrl.displayObjCtrl.OnRemoveEntity(entity as LevelPlayRealityEntity);
            //移除四叉树
            _entityQuadTree.Remove(entity);
            //移除bvhtree
            bool ok = triggerRangeEntitys.Remove(entity);
            if (ok)
            {
                _triggerBVHTree.Remove(entity);
            }
        }


        /// <summary>
        /// 实体刷新位置时和旋转的时候
        /// </summary>
        /// <param name="entity"></param>
        protected void OnEntityRefreshPosOrRot(LevelPlayBaseEntity entity)
        {
            //更新四叉树
            var v2 = GameMathUtil.LogicPos2UnityPosV2(entity.x, entity.z);
            _entityQuadTree.Update(entity, v2);
            //尝试更新纯显示数据
            regionCtrl.displayObjCtrl.UpdateEntity(entity as LevelPlayRealityEntity);

            //更新bvhtree
            if (triggerRangeEntitys.TryGetValue(entity, out var triggerRect))
            {
                var bvhBounds = entity.GetBVHBounds(triggerRect.rect, triggerRect.isRotatable);
                _triggerBVHTree.Update(entity, bvhBounds);
            }
        }

        #endregion

        #region 控制器声明周期period

        protected override void OnDispose()
        {
            DisposeLogic();

            RemoveMsgListener();

            _characterEntity = null;

            if (_deadingEntitys.Count > 0)
            {
                // 如果有正在死亡的实体，直接完成死亡计时器
                List<uint> deading = ListPool<uint>.Get();
                deading.AddRangValue(_deadingEntitys);
                for (var i = 0; i < deading.Count; i++)
                {
                    // 直接完成死亡计时器
                    deading[i].StopTimer(true);
                }
                ListPool<uint>.Put(deading);
                _deadingEntitys.Clear();
            }

            foreach (var kv in heroEntities)
            {
                kv.Value.Free();
            }
            heroEntities.Clear();

            foreach (var kv in entitys)
            {
                kv.Value.Free();
            }
            entitys.Clear();
            foreach (var kv in mcidEntityMap)
            {
                ListPool<LevelPlayBaseEntity>.Put(kv.Value);
            }
            mcidEntityMap.Clear();

            _entityQuadTree = null;
            _triggerBVHTree = null;

            if (headIndicator != null)
            {
                UnityEngine.Object.Destroy(headIndicator.gameObject);
            }

            // 关闭对象池
            ManagerCenter.Entity.DisableGroup((int)EntityPoolGroupType.LevelEntity);
        }

        /// <summary>
        /// 预加载初始的实体
        /// </summary>
        /// <returns></returns>
        protected virtual async UniTask AddEntityPreload()
        {
            entityHolder = new GameObject("Entitys").transform;

            //加载场景中的实体并创建.
            List<UniTask> tasks = ListPool<UniTask>.Get();
            foreach (var kv in heroEntities)
            {
                tasks.Add(kv.Value.LoadAndInstantiate(entityHolder));
                var heroEntity = kv.Value;
                if (heroEntity.isMine && _characterEntity == null)
                {
                    _characterEntity = heroEntity;
                }
            }
            foreach (var e in entitys)
            {
                if (e.Value is LevelPlayRealityEntity entity)
                {
                    tasks.Add(entity.LoadAndInstantiate(entityHolder));
                }
            }
            await UniTask.WhenAll(tasks);
        }


        protected override void OnModuleGameplayInit()
        {
            // 激活对象池
            ManagerCenter.Entity.EnableGroup((int)EntityPoolGroupType.LevelEntity);

            // 添加实体预加载
            this.regionCtrl.sceneCtrl.AddPreloadAfterScene(AddEntityPreload);

            //创建初始的实体对象集
            var levelRegion = this.regionCtrl.levelRegion;
            foreach (var dynEntity in levelRegion.dynHeroEntitys)
            {
                var heroEntity = LevelEntityFactory.CreateEntity(dynEntity);
                heroEntities.Add(heroEntity.id, heroEntity);
            }
            foreach (var dynEntity in levelRegion.dynLevelEntitys)
            {
                var normalEntity = LevelEntityFactory.CreateEntity(dynEntity);
                //id映射
                entitys.Add(normalEntity.id, normalEntity);
                //mcid映射
                if (!mcidEntityMap.TryGetValue(dynEntity.mcid, out var entityList))
                {
                    entityList = ListPool<LevelPlayBaseEntity>.Get();
                    mcidEntityMap.Add(dynEntity.mcid, entityList);
                }
                entityList.Add(normalEntity);
            }
        }


        protected override void OnSceneLoaded()
        {
            dynParamPrcoesses = RegisterDynParamProcess.CreateDynParamProcesses(this.regionCtrl);

            var boundsRect = regionCtrl.navigationCtrl.boundsRect;
            _entityQuadTree = new QuadTree<LevelPlayBaseEntity>(boundsRect);

            _triggerBVHTree = new BVHTree2D<LevelPlayBaseEntity>(BVHBounds2D.FromRect(boundsRect));

            foreach (var e in heroEntities)
            {
                OnHeroEntityCreate(e.Value);
            }
            foreach (var e in entitys)
            {
                var entity = e.Value;
                OnEntityCreate(entity);
            }

            InitLogicInternal();

            // 头顶指示器
            headIndicator = GameObject.Instantiate(levelPlayCtrl.permanentResource.prefabHeadIndicator).AddComponent<PositionConstraint>();
            // 高度偏移
            //headIndicator.translationOffset = new Vector3(0, 1.2f, 0);
            headIndicator.AddSource(new ConstraintSource() { weight = 1 });
            headIndicator.constraintActive = true;
            SetHeadIndicatorOn(false);

            activeLogicUpdate = true;
        }

        protected override void OnUpdate(float deltaTime)
        {
            foreach (var e in entitys)
            {
                var entity = e.Value;
                if (!entity.active)
                {
                    continue;
                }
                entity.OnUpdate(deltaTime);
            }
            foreach (var kv in heroEntities)
            {
                kv.Value.OnUpdate(deltaTime);
            }

            UpdateLogicInternal(deltaTime);
            UpdateDropItems(deltaTime);
        }

        #endregion


        public LevelPlayBaseEntity GetEntityByMcid(int id)
        {
            if (mcidEntityMap.TryGetValue(id, out var entitys))
            {
                if (entitys.Count == 0)
                {
                    return null;
                }
                if (entitys.Count > 1)
                {
                    LogGame.LogError("通过mcid获取实体时，发现了多个相同mcid的实体，可能有克隆出来的实体，目前克隆出来的实体不支持直接通过mcid获取，因为包含多个，请找程序商量解决方式。");
                }
                return entitys[0];
            }
            return null;
        }

        /// <summary>
        /// 显示掉落物表现
        /// </summary>
        /// <param name="srcEntityId"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public async UniTask ShowEntityDrop(int srcEntityId, List<ItemShowPOD> items)
        {
            if (entitys.TryGetValue(srcEntityId, out var entity))
            {
                //确定掉落物随机位置（以实体为圆心的圆圈内）
                var bindCom = entity.GetComponent<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
                var effectStartPos = bindCom.GetBindPoint(EntityBindPointCommonType.Middle).position;
                List<Vector3> landPoints = ListPool<Vector3>.Get();
                List<UniTask> tasks = ListPool<UniTask>.Get();
                GameScenePlayUtil.GetRandomPointInCircleOnGround(effectStartPos, GameGlobalConst.SceneDropRandomRadius, items.Count, landPoints);
                //创建所有掉落的展示对象
                for (int i = 0; i < items.Count; i++)
                {
                    var itemPOD = items[i];
                    var dropItemPlay = ClassPool<LevelDropItemPlay>.Get();
                    //加入帧刷队列
                    //掉落表现是基于帧刷的，没有使用tween
                    _dropItemPlays.Add(dropItemPlay);
                    //创建动画任务
                    tasks.Add(dropItemPlay.Show(itemPOD.cid, itemPOD.num, effectStartPos, landPoints[i]));
                }
                //掉落物空间内部帧刷会修改任务完成情况
                //等待所有展示动画播放完毕
                await UniTask.WhenAll(tasks);
                ListPool<UniTask>.Put(tasks);
                ListPool<Vector3>.Put(landPoints);
            }
        }

        /// <summary>
        /// 刷新掉落物表现
        /// </summary>
        /// <param name="deltaTime"></param>
        private void UpdateDropItems(float deltaTime)
        {
            if (_dropItemPlays.Count > 0)
            {
                for (int i = _dropItemPlays.Count - 1; i >= 0; i--)
                {
                    var item = _dropItemPlays[i];
                    item.Update(deltaTime);
                    if (item.isExpired)
                    {
                        item.Release();
                        _dropItemPlays.RemoveAt(i);
                    }
                }
            }
        }

        /// <summary>
        /// 改变交互指示器所指的实体，同时改变指示器的显隐
        /// </summary>
        /// <param name="isActive"></param>
        /// <param name="entity"></param>
        public void SetHeadIndicatorOn(bool isActive, LevelPlayRealityEntity entity = null)
        {
            //显示或隐藏指示器
            headIndicator.gameObject.SetActive(isActive);
            //改变指示器指示的实体
            if (isActive)
            {
                var constraintSource = headIndicator.GetSource(0);
                var bindPointCom = entity.GetComponent<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
                constraintSource.sourceTransform = bindPointCom.GetBindPoint(EntityBindPointCommonType.Top);
                headIndicator.SetSource(0, constraintSource);

                if (_indicateEntity != entity)
                {
                    _indicateEntity?.OnIndicatorChange(false);
                    entity.OnIndicatorChange(true);
                    _indicateEntity = entity;
                }
            }
            else
            {
                _indicateEntity?.OnIndicatorChange(false);
                _indicateEntity = null;
            }
        }

        public void PlayRevive(long pid)
        {
            foreach (var kv in heroEntities)
            {
                var entity = kv.Value;
                var dynHeroEntity = entity.GetDynEntityData() as DynLevelHeroEntity;
                if (dynHeroEntity.playerId == pid)
                {
                    entity.GetAnimationComponent().ResetAnim();
                    break;
                }
            }
        }
    }
}
